{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {
    "pycharm": {
     "name": "#%% raw\n"
    },
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. _nb_video:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Video"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Images are fantastic, but since optimization happens over time, videos can capture the optimization process itself often in a better way.\n",
    "In `pymoo` we offer a wrapper around `matplotlib` to combine complex plots and put them together in a video (a different way than the animation package does it). This is, however, more computationally expensive, but makes recording very simple."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "To enable video support, you have to install `pyrecorder` by\n",
    "\n",
    "```\n",
    "pip install -U pyrecorder\n",
    "```\n",
    "\n",
    "Because our recording tool has some dependencies, not every regular `pymoo` user would be interested in, we have decided to outsource the recording to another third-party library."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "For instance, let us record a short video with only three frames (randomly created scatter plots):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from pyrecorder.recorder import Recorder\n",
    "from pyrecorder.writers.video import Video\n",
    "\n",
    "from pymoo.algorithms.moo.nsga2 import NSGA2\n",
    "from pymoo.visualization.scatter import Scatter\n",
    "\n",
    "\n",
    "with Recorder(Video(\"example.mp4\")) as rec:\n",
    "\n",
    "    for k in range(10):\n",
    "        X = np.random.random((100, 2))\n",
    "        Scatter(title=str(k)).add(X).do()\n",
    "        rec.record()\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Or recording a video after the run has finished:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from pymoo.problems import get_problem\n",
    "from pymoo.optimize import minimize\n",
    "\n",
    "problem = get_problem(\"zdt1\")\n",
    "\n",
    "algorithm = NSGA2(pop_size=100, eliminate_duplicates=True)\n",
    "\n",
    "ret = minimize(problem,\n",
    "               algorithm,\n",
    "               termination=('n_gen', 100),\n",
    "               seed=1,\n",
    "               save_history=True,\n",
    "               verbose=False)\n",
    "\n",
    "# use the video writer as a resource\n",
    "with Recorder(Video(\"ga.mp4\")) as rec:\n",
    "\n",
    "    # for each algorithm object in the history\n",
    "    for entry in ret.history:\n",
    "        sc = Scatter(title=(\"Gen %s\" % entry.n_gen))\n",
    "        sc.add(entry.pop.get(\"F\"))\n",
    "        sc.add(entry.problem.pareto_front(), plot_type=\"line\", color=\"black\", alpha=0.7)\n",
    "        sc.do()\n",
    "\n",
    "        # finally record the current visualization to the video\n",
    "        rec.record()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "The callback directive can be used to initiate a video by `Video(Streamer())` to stream the current algorithm state directly to the screen.\n",
    "This allows the streaming of the current status of the algorithm."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from pymoo.algorithms.soo.nonconvex.ga import GA\n",
    "from pymoo.core.callback import Callback\n",
    "from pymoo.problems import get_problem\n",
    "from pymoo.optimize import minimize\n",
    "from pymoo.visualization.pcp import PCP\n",
    "from pyrecorder.recorder import Recorder\n",
    "from pyrecorder.writers.streamer import Streamer\n",
    "\n",
    "\n",
    "class MyCallback(Callback):\n",
    "\n",
    "    def __init__(self) -> None:\n",
    "        super().__init__()\n",
    "        self.rec = Recorder(Streamer(sleep=0.1))\n",
    "\n",
    "    def notify(self, algorithm):\n",
    "        problem = algorithm.problem\n",
    "\n",
    "        pcp = PCP(title=(\"Gen %s\" % algorithm.n_gen, {'pad': 30}),\n",
    "                  bounds=(problem.xl, problem.xu),\n",
    "                  labels=[\"$x_%s$\" % k for k in range(problem.n_var)]\n",
    "                  )\n",
    "        pcp.set_axis_style(color=\"grey\", alpha=0.5)\n",
    "\n",
    "        pcp.add(algorithm.pop.get(\"X\"), color=\"black\", alpha=0.8, linewidth=1.5)\n",
    "        if algorithm.off is not None:\n",
    "            pcp.add(algorithm.off.get(\"X\"), color=\"blue\", alpha=0.8, linewidth=0.5)\n",
    "\n",
    "        pcp.add(algorithm.opt.get(\"X\"), color=\"red\", linewidth=4)\n",
    "        pcp.do()\n",
    "\n",
    "        self.rec.record()\n",
    "\n",
    "\n",
    "problem = get_problem(\"rastrigin\", n_var=10)\n",
    "\n",
    "algorithm = GA(pop_size=50, eliminate_duplicates=True, callback=MyCallback())\n",
    "\n",
    "ret = minimize(problem,\n",
    "               algorithm,\n",
    "               termination=('n_gen', 50),\n",
    "               seed=1,\n",
    "               verbose=False)\n",
    "\n"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 4
}
